#include <iostream>
using namespace std;
#include <cmath>
#include<stdlib.h>

//ubuntu 
//gcc -o esqueleto esqueleto.c -lglut -lGLU -lGL -lm
//windows
//gcc -o esqueleto esqueleto.c -lglut32 -lglu32 -lopengl32

#if defined(_WIN32)
#include <windows.h>
#include <gl/Gl.h>
#include <gl/Glu.h>
#include <gl/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif

GLfloat dir, esq, cima, baixo;
GLint view_w, view_h;
int n;
double ds = 0.1;
double x[100], y[100];
double zt, zx;

double * tridiagonal(double * a, double * b, double * c, double * r, int n) {
	double * x = new double[n];
	
	for(int j = 1; j < n; j++) {
		double m = a[j] / b[j-1];
		if(m == 0) continue;
		b[j] -= m * c[j-1];
		r[j] -= m * r[j-1];
	}
	
	for(int j = n-1; j >= 0; j--) {
		x[j] = (r[j] - c[j] * x[j+1]) / b[j];
	}
	
	return x;
}

struct cubica {
	double a, b, c, d, x0;
	double operator()(double x) { x -= x0; return a*x*x*x + b*x*x + c*x + d; }
};

cubica * spline(double * x, double * y, int n) {
	double * h = new double[n-1];
	
	for(int j = 0; j < n-1; j++) h[j] = x[j+1] - x[j];
	
	double * a = new double[n];
	double * b = new double[n];
	double * c = new double[n];
	double * r = new double[n];
	
	a[0] = c[0] = r[0] = 0;
	b[0] = 1;
	a[n-1] = c[n-1] = r[n-1] = 0;
	b[n-1] = 1;
	
	for(int j = 1; j < n-1; j++) {
		a[j] = h[j-1];
		b[j] = 2 * (h[j-1] + h[j]);
		c[j] = h[j];
		r[j] = 6 * ((y[j+1] - y[j]) / h[j] - (y[j] - y[j-1]) / h[j-1]);
	}
	
	double * s = tridiagonal(a, b, c, r, n);
		
	cubica * p = new cubica[n-1];
	
	for(int i = 0; i < n-1; i++) {
		p[i].x0 = x[i];
		p[i].a = (s[i+1] - s[i]) / (6 * h[i]);
		p[i].b = s[i] / 2;
		p[i].c = (y[i+1] - y[i]) / h[i] - (2 * s[i] + s[i+1]) * h[i] / 6;
		p[i].d = y[i];
	}
	
	delete [] a;
	delete [] b;
	delete [] c;
	delete [] r;
	delete [] s;
	
	return p;
}

void inicializa (void){ 
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // define a "Cor de Fundo" da janela
	cima = 4.0f;
	esq = -1.0f;
	dir = 9.0f;
	baixo = -3.0f;
	zt = 1;
	zx = 1;
}

void AlteraTamanhoJanela(GLsizei w, GLsizei h){ 
	glViewport(0, 0, w, h);
	view_w = w;
	view_h = h;                   
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D (esq, dir, baixo, cima);
}

void TeclasEspeciais(int key, int x, int y){
	if(key == GLUT_KEY_UP) {
		baixo += ds;
		cima += ds;
		glMatrixMode(GL_PROJECTION);	
		glLoadIdentity();
		gluOrtho2D (esq, dir, baixo, cima);
	}
	if(key == GLUT_KEY_LEFT) {
		esq -= ds;
		dir -= ds;
		glMatrixMode(GL_PROJECTION);	
		glLoadIdentity();
		gluOrtho2D (esq, dir, baixo, cima);
	}
	if(key == GLUT_KEY_RIGHT) {
		esq += ds;
		dir += ds;
		glMatrixMode(GL_PROJECTION);	
		glLoadIdentity();
		gluOrtho2D (esq, dir, baixo, cima);
	}
	if(key == GLUT_KEY_DOWN) {
		baixo -= ds;
		cima -= ds;
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D (esq, dir, baixo, cima);
	}
	glutPostRedisplay();
}

void Teclado(unsigned char k, int x, int y){
	if (k == 27){
		printf ("exit...");
		exit(0);
	}
	if (k == 13){
		inicializa();
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D (esq, dir, baixo, cima);
		glutPostRedisplay();
		
	}
}

void GerenciaMouse(int button, int state, int x, int y){
	//printf("%d %d\n", x, y);
	if (button == GLUT_LEFT_BUTTON){
		if (state == GLUT_DOWN) {
			zt += 0.1;
			zx += 0.1;
		}
	}
	if (button == GLUT_RIGHT_BUTTON){
		if (state == GLUT_DOWN) {
			if(zt > 0.2){
				zt -= 0.1;
				zx -= 0.1;
			}
		}
	}
	glutPostRedisplay();
}

void Plota(){
	double j;
	glColor3f(0,1,0);
	for( j = -100; j <= 100; j+= 1){
		if(!(j >= -0.5 && j <= 0.5)){
			glBegin(GL_LINES);
			glVertex2f(j*zt , -100);
			glVertex2f(j*zt , 100);
		}	
	}
	for(j = -100; j <= 100; j+= 1){
			if(!(j >= -0.5 && j <= 0.5)){
			glBegin(GL_LINES);
			glVertex2f(-100 , j*zx);
			glVertex2f(100 , j*zx);	
		}
	}

	cubica * c = spline(x, y, n);
	glColor3f(1,0,1);
	glBegin(GL_LINES);
	double temp1 = 1, temp2 = c[0](1);
	for(int i = 0; i < n-1; i++) {
		for(float t = x[i]; t < x[i+1]; t += 0.001f) {
			
			glVertex2f(temp1*zt, temp2*zx);
			glVertex2f(t*zt, c[i](t)*zx);		
			temp1 = t;
			temp2 = c[i](t);
		}
	}
}

void principal(void){
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0,0,0);
	glBegin(GL_LINES);
	glVertex2f(0, -100);
	glVertex2f(0, 100);	
	glBegin(GL_LINES);
	glVertex2f(-100, 0);
	glVertex2f(100, 0);

	Plota();
	
   	glEnd();
	glFlush();
	glColor3f(0,0,0);
	glutSwapBuffers();
}

int main(int argc, char** argv){
	cin>>n;
	for(int i = 0; i < n; i ++) cin>>x[i]>>y[i];
  	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize(600, 600);
	glutInitWindowPosition(300, 200);
	glutCreateWindow("Grafico");
	glutDisplayFunc(principal);
	glutReshapeFunc(AlteraTamanhoJanela);
	glutSpecialFunc(TeclasEspeciais);
	glutKeyboardFunc(Teclado);
	glutMouseFunc(GerenciaMouse);	
	inicializa();
	glutMainLoop();
	
	return 0;
}
